package me.zhengjie.modules.quartz.task;

import cn.hutool.core.date.DateTime;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.fund.domain.UserFundLog;
import me.zhengjie.modules.fund.repository.UserFundLogRepository;
import me.zhengjie.modules.fund.service.UserFundFlowService;
import me.zhengjie.modules.fund.service.UserFundLogService;
import me.zhengjie.modules.fund.service.UserFundService;
import me.zhengjie.modules.fund.service.dto.UserFundDto;
import me.zhengjie.modules.fund.service.dto.UserFundFlowDto;
import me.zhengjie.modules.fund.service.dto.UserFundFlowQueryCriteria;
import me.zhengjie.modules.fund.service.dto.UserFundQueryCriteria;
import me.zhengjie.utils.DateUtil;
import me.zhengjie.utils.ElAdminConstant;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 用户基金日志任务
 * 每晚把当前的用户基金日志做一个快照，并计算当日的盈亏
 */
@Slf4j
@Component
public class UserFundLogTask {

    @Resource
    private UserFundService userFundService;

    @Resource
    private UserFundFlowService userFundFlowService;

    @Resource
    private UserFundLogService userFundLogService;

    @Resource
    private UserFundLogRepository userFundLogRepository;

    @Transactional(rollbackFor = Exception.class)
    public void run() {
        int pageNum = 0;
        int pageSize = 100;

        DateTime yesterday = me.zhengjie.utils.DateUtil.getYesterdayDate();
        DateTime theDayBeforeYesterdayDate = DateUtil.getTheDayBeforeYesterdayDate();

        Page<UserFundDto> pageUserFunds;
        do {
            PageRequest page = PageRequest.of(pageNum, pageSize, Sort.Direction.DESC, "id");
            pageUserFunds = userFundService.queryAll(new UserFundQueryCriteria(), page);

            List<UserFundDto> userFunds = pageUserFunds.getContent();
            saveUserFundLog(userFunds, yesterday, theDayBeforeYesterdayDate);
            pageNum++;
        } while (pageUserFunds.hasNext());
    }

    private void saveUserFundLog(List<UserFundDto> userFundDtos, Date yesterday, Date theDayBeforeYesterday) {

        for (UserFundDto userFundDto : userFundDtos) {
            if (userFundDto.getFundName().equals("合计")) {
                continue;
            }
            UserFundLog userFundLog = new UserFundLog();
            userFundLog.setDate(yesterday);
            userFundLog.setUserId(userFundDto.getUserId());
            userFundLog.setFundCode(userFundDto.getFundCode());
            userFundLog.setFundName(userFundDto.getFundName());
            userFundLog.setFundType(userFundDto.getFundType());
            userFundLog.setCount(userFundDto.getCount());
            userFundLog.setNewestAmount(userFundDto.getNewestAmount());
            userFundLog.setNewestNetValue(userFundDto.getNewestNetValue());
            userFundLog.setNewestUpdatedDate(userFundDto.getNewestUpdatedDate());
            userFundLog.setPrincipalAmount(userFundDto.getPrincipalAmount());
            userFundLog.setPrincipalNetValue(userFundDto.getPrincipalNetValue());
            userFundLog.setPurchaseChannel(userFundDto.getPurchaseChannel());

            // 在途纪录
            List<UserFundFlowDto> lstUserFundFlows = getOnOrderFlows(userFundDto);
            double onOrderAmount = lstUserFundFlows.stream().map(UserFundFlowDto::getOperateAmount).mapToDouble((s) -> s.doubleValue()).sum();
            userFundLog.setOnorderAmount(BigDecimal.valueOf(onOrderAmount));

            // 昨天日志
            UserFundLog theDayBeforeYesterdayLog = userFundLogRepository.findByUserIdAndFundCodeAndDate(userFundDto.getUserId(), userFundDto.getFundCode(), theDayBeforeYesterday);
            if (Objects.nonNull(theDayBeforeYesterdayLog)) {
                BigDecimal onOrderAmountOfTheDayBeforeYesterday = Objects.isNull(theDayBeforeYesterdayLog.getOnorderAmount()) ? BigDecimal.ZERO : theDayBeforeYesterdayLog.getOnorderAmount();
                BigDecimal amountOfTheDayBeforeYesterday = theDayBeforeYesterdayLog.getNewestAmount().add(onOrderAmountOfTheDayBeforeYesterday);

                // 盈利金额 = 当前最新金额 + 在途金额 - 昨日金额
                userFundLog.setProfitAmount(userFundLog.getNewestAmount().add(userFundLog.getOnorderAmount()).subtract(amountOfTheDayBeforeYesterday));
                userFundLog.setProfitRate(userFundLog.getProfitAmount().divide(amountOfTheDayBeforeYesterday, 4, BigDecimal.ROUND_HALF_UP));
            }

            userFundLogService.save(userFundLog);
        }
    }

    private List<UserFundFlowDto> getOnOrderFlows(UserFundDto userFundDto) {
        UserFundFlowQueryCriteria query = new UserFundFlowQueryCriteria();
        query.setUserId(userFundDto.getUserId());
        query.setFundCode(userFundDto.getFundCode());
        query.setStatus(ElAdminConstant.UserFundFlowStatus.OnOrder);

        List<UserFundFlowDto> lstUserFundFlows = userFundFlowService.queryAll(query);
        return lstUserFundFlows;
    }
}
